import { del, get, post, postGet, put } from '@/useHttp';
import type { ActionType, ProColumns, ProFormInstance } from '@ant-design/pro-components';
import { ProTable } from '@ant-design/pro-components';
import { useEffect, useRef, useState } from 'react';
import React from 'react';
import EditForm from '@/components/EditForm';
import { Button, Popconfirm, Space, Table } from 'antd'
import exportToJsonExcel from './exp_xlsx';
import Import from './import';
import { DownloadOutlined, FileExcelOutlined } from '@ant-design/icons';
import { GetRowKey } from 'antd/es/table/interface';

type propTypes<T = any> = {
  /**
   * 表格数据源(与url二选一)
   */
  dataSource?: T[];
  /** 表格列配置
   * 
   * title: 表单项标题
   * 
   * valueType: 表单项类型, 查询编辑时使用, 如: text, digit, password, date, datetime, select, textarea, switch, radio
   * 
   * editable: 不在EditForm中出现
   * 
   * disable: 在EditForm中出现,但不可编辑
   * 
   * request: 与 params 配合, 实现读取数据, 作为 valueEnum 的值
   * 
   * @example render
   * ```tsx
   * render: (dom, entity, index, action, schema) => {
   *    // 值 >0 红色
   *    if ((entity as any).DiffIn !== 0) {
   *      dom = <span style={{ color: 'red' }}>{dom}</span>
   *    }
   *    return dom
   *  }, // 自定义渲染
   * ```
   * 
   * @example fieldProps 表单项的属性(如: 日期型的 format)
   * ```tsx
   * fieldProps: {
   *   dateFormat: 'YYYY-MM-DD HH:mm:ss', // 日期格式化
   * } 
   * ```
   */
  columns: ProColumns<T>[];
  /**
   * 
   * @returns 编辑/新增弹窗时调用
   */
  onOpen?: () => void;
  /**
   * request 请求时用的 url(查,增,改删)(与 dataSource 二选一)
   */
  url?: string;
  /**
   * 查询请求参数
   */
  params?: {};
  /**
   * 隐藏工具栏
   */
  hideToolbar?: boolean;
  hideImport?: boolean;
  hideExport?: boolean;
  hideTemplate?: boolean;
  /**
   * 隐藏操作列
   */
  hideAction?: boolean;
  hideAddButton?: boolean;
  hideEditButton?: boolean;
  hideDeleteButton?: boolean;
  /** 
   * 扩展操作列 
   * @example
   * ``` tsx
   * extractAction={(_, entity, index, action): React.ReactNode[] => {
   *   return [
   *     <Button key={index} color='primary' variant='dashed' onClick={() => { action('edit', entity) }}>忽略检查</Button>,
   *     <Button key={index} color='danger' variant='dashed' onClick={() => { action('edit', entity) }}>出入金</Button>,
   *   ];
   * }}
   * ```
   */
  extractAction?: (dom: React.ReactNode, entity: any, index: number, action: any | undefined) => React.ReactNode[];
  /**
   * 数据行Key(默认 ID)
   * ```
   * const generateRowKey = (record: OrderField) => `${record.SessionID}-${record.FrontID}-${record.OrderRef}`;
   * ```
   */
  rowKey: string | GetRowKey<T>;
  /**
   * 是否多行选择
   */
  multi?: boolean;
  /**
   * 多行选择时渲染
   * @param selectedRowKeys 选择 Keys(默认 ID)
   * @example 
   * ``` tsx
   *  tableAlertOptionRender={(keys: React.Key[], actionRef: React.MutableRefObject<ActionType>) => (
   *    <Button type='primary' onClick={
   *      async () => {
   *        const success = await inoutByID(keys as number[])
   *        if (success) message.success('出金成功')
   *          actionRef.current.reload()
   *      }
   *  }>出金</Button>
   *  )}
   * ```
   * @returns React.ReactNode
   */
  tableAlertOptionRender?: (selectedRowKeys: React.Key[], actionRef: React.MutableRefObject<ActionType>) => React.ReactNode;
  /**
   * 菜单增加按钮(传递 formRef 给应用层使用)
   * 
   * @example 
   *  ``` tsx
   *  extractMenu={(formRef: React.RefObject<ProFormInstance>, actionRef: React.RefObject<ActionType>)=>{
   *    return [{
   *    key: 'login',
   *    label: <Button color='danger' variant="solid" onClick={
   *      async () => {
   *        const { success } = await post<{ success: boolean }>('/api/open', formRef.current?.getFieldsValue())
   *        if (success) {
   *          notification.success({
   *            message: '执行成功',
   *            description: '请在30秒后刷新页面, 查看各柜台状态.',
   *            placement: 'top',
   *          })
   *        }
   *        actionRef.current.reload() 
   *      }
   *    }>柜台登录</Button>
   *  }]}}
   *  ```
   * @returns { key: string, label: {} }[]
   */
  extToolbar?: (formRef: React.RefObject<ProFormInstance>, actionRef: React.RefObject<ActionType>) => { key: string; label: {} }[];

  /**
   * 隐藏分页器(显示所有数据)
   */
  hidePagination?: boolean,
  pageSize?: number;

  /**
   * 隐藏搜索表单
   */
  hideSearchBox?: boolean;

  /**
   * 基于 ProTable 的属性
   */
  fieldProps?: {};

  /**
   * 使用 POST 请求获取数据
   */
  usePostGET?: boolean;

  /**
   * 定时刷新间隔（毫秒）
   */
  refreshInterval?: number;
};

export type HFColumns = ProColumns & { editType?: string };

const formRef = React.createRef<ProFormInstance>();

const DataTable = (props: propTypes) => {
  const actionRef = useRef<ActionType>({} as ActionType);
  const columns: HFColumns[] = [
    { // 序号列
      dataIndex: 'index',
      valueType: 'indexBorder',
      width: 40,
      key: 'index',
      fixed: 'left',
    },
    ...props.columns, // 应用声明的列
    { // 操作列
      key: 'operation',
      title: '操作',
      valueType: 'option',
      width: 120,
      fixed: 'right',
      render: (_, record, index, action) => {
        // 判断 props.rowKey 是否为 string, 是则取值, 不是则按照函数执行并返回值
        const key = typeof props.rowKey === 'string' ? JSON.stringify({ [props.rowKey]: record[props.rowKey] }) : (props.rowKey as any)(record);
        const where = typeof props.rowKey === 'string' ? { [props.rowKey]: record[props.rowKey] } : record;

        return [
          // 扩展操作列
          props.extractAction?.(_, record, index, action),
          // 编辑按钮
          props.hideEditButton || (<a key={'editable' + index} >
            <EditForm
              key={index}
              data={record}
              title={'编辑'}
              columns={columns}
              onFinish={async (values) => {
                const success = await put(props.url || '', where, values)
                if (success) {
                  // 刷新数据
                  action?.reload();
                }
                return success
              }}
              // 窗口显示时执行应用定义的事件
              onOpen={props?.onOpen}
            />
          </a>),
          // 删除按钮
          props.hideDeleteButton || (<Popconfirm key={index} title="确认"
            description={'删除记录 ' + key + ' 吗 ?'}
            onConfirm={async () => {
              // 以 props.rowKey 为主键删除, 构造 map[string]string 的参数
              const success = await del(props.url || '', where)
              if (success) {
                action?.reload(); // 删除成功后刷新数据
              }
            }}
            // onCancel={cancel}
            okText="确认"
            cancelText="取消">
            <a
              key={'delete' + index}
            >
              删除
            </a>
          </Popconfirm>),
        ]
      }
    }
  ]
  const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);

  columns.forEach((item: ProColumns) => {
    // 如果列类型为选择框，则显示搜索框
    switch (item.valueType) {
      case 'select':
        item.fieldProps = {
          ...item.fieldProps,
          showSearch: true,
        }
        break;
      case 'checkbox':
        item.fieldProps = {
          options: [
            {
              label: '是',
              value: true,
            },
            {
              label: '否',
              value: false,
            }
          ],
          ...item.fieldProps,
        }
        break;
      case 'switch':
        item.fieldProps = {
          checkedChildren: '是',
          unCheckedChildren: '否',
          ...item.fieldProps,
        }
        break;
    }
  })

  useEffect(() => {
    let intervalId: NodeJS.Timeout;

    if (props.refreshInterval) {
      intervalId = setInterval(() => {
        actionRef.current?.reload();

      }, props.refreshInterval);
    }

    return () => {
      clearInterval(intervalId);
    };
  }, [props.refreshInterval]);

  return (
    <>
      <ProTable
        // 是否显示搜索表单
        search={props.hideSearchBox ? false : {}}
        // 是否显示分页器, 应用定义的页大小
        pagination={props.hidePagination ? false : { showSizeChanger: true, pageSize: props.pageSize || 10 }}
        // 是否显示操作列
        columns={columns.filter((item) => props.hideAction ? item.key !== 'operation' : item)}

        // 行标识的列名
        rowKey={props.rowKey}

        // 隐藏工具栏
        options={props.hideToolbar ? false : { density: false, fullScreen: false, reload: true, setting: false }}

        // 多行选择
        rowSelection={props.multi && {
          // 自定义选择项参考: https://ant.design/components/table-cn/#components-table-demo-row-selection-custom
          // 注释该行则默认不显示下拉选项
          selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT],
          // defaultSelectedRowKeys: [0],
          onChange(selectedRowKeys, selectedRows, info) {
            setSelectedRowKeys(selectedRowKeys)
          },
        }}

        // 自定义 table 的 alert 的操作(多行选择时渲染)
        tableAlertOptionRender={(() => props.tableAlertOptionRender?.(selectedRowKeys, actionRef as any))}

        actionRef={actionRef}
        formRef={formRef as any}

        // 应用定义的数据源
        dataSource={props.dataSource}
        // 应用定义的请求方法
        request={async (params, sort, filter) => {
          if (props.hidePagination) { // 隐藏分页器, 显示所有数据
            delete params.current
            delete params.pageSize
          }
          let url = props.url
          if (props.usePostGET) url = props.url?.replace('/api/', '/api/get/')
          return (props.usePostGET ? postGet : get)(url || '', { ...params, ...props.params }, '', sort, filter);
        }}
        // 横向滚动条
        scroll={{ x: 'max-content' }}
        // 自定义工具栏
        toolbar={{
          menu: {
            type: 'inline',
            activeKey: 'impModal',
            items: [...props.hideToolbar ? [] : [
              props.hideImport || {
                key: 'import',
                label: <Import url={props?.url || ''} columns={props.columns} onSuccess={() => actionRef.current?.reload()} />,
              },
              props.hideExport || {
                key: 'export',
                label: <Button type='primary' icon={<DownloadOutlined />} onClick={async () => {
                  // 导出数据
                  if (props.dataSource) {
                    exportToJsonExcel(props.dataSource)
                  } else {
                    // 查询导出
                    const vals = formRef.current?.getFieldsValue()
                    const { data } = await get(props?.url || '', vals)
                    if (data.length > 0) {
                      // 检查返回数据中, 不需要导出的字段名以及字段名转换
                      const res = data.map((item: any) => {
                        const val = {} as any
                        // 字段顺序与columns一致
                        props.columns.forEach((col) => {
                          if (col.dataIndex) {
                            val[col.title as string] = item[col.dataIndex]
                          }
                        })
                        return val
                      });
                      exportToJsonExcel(res)
                    }
                  }
                }}>
                  导出
                </Button>
              },
              props.hideTemplate || {
                key: 'impModal',
                label: <Button type='dashed' icon={<FileExcelOutlined />} onClick={async () => {
                  if (props.dataSource) {
                    exportToJsonExcel(props.dataSource[0])
                  } else {
                    const { data } = await get(props.url || '', { current: 1, pageSize: 1 }) // 只取1条数据(无数据时返回为null)
                    if (data.length > 0) {
                      // 检查返回数据中, 不需要导出的字段名以及字段名转换
                      const res = data.map((item: any) => {
                        const val = {} as any
                        // 字段顺序与columns一致
                        props.columns.forEach((col) => {
                          if (col.dataIndex) {
                            val[col.title as string] = item[col.dataIndex]
                          }
                        })
                        return val
                      });
                      exportToJsonExcel(res)
                    }
                  }
                }}>
                  模板
                </Button>
              }],
            // 应用定义的菜单
            ...(props.extToolbar?.(formRef, actionRef) ?? []) as any
            ],
          },
          // 隐藏/显示新建按钮
          actions: props.hideAction || props.hideAddButton ? [] : [
            <EditForm
              key={'new'}
              title={'新建'}
              columns={columns}
              data={{}}
              onFinish={async (values: any) => {
                const { success } = await post(props.url || '', values);
                if (success && actionRef.current) {
                  // 刷新数据
                  actionRef.current.reload();
                }
                return success; // 关闭
              }}
              // 打开表单时, 调用应用的事件(如: 打开前清空表单)
              onOpen={props.onOpen}
            />,
          ],
        }}
        // 基于 ProTable 的参数
        {...props.fieldProps}
      />
    </>
  );
};

export default DataTable;
